home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / a_utils / yacc / flexyacc / aflex.lha / aflex / src / parse.y < prev    next >
Text File  |  1991-05-16  |  16KB  |  662 lines

  1. -- Copyright (c) 1990 Regents of the University of California.
  2. -- All rights reserved.
  3. --
  4. -- This software was developed by John Self of the Arcadia project
  5. -- at the University of California, Irvine.
  6. --
  7. -- Redistribution and use in source and binary forms are permitted
  8. -- provided that the above copyright notice and this paragraph are
  9. -- duplicated in all such forms and that any documentation,
  10. -- advertising materials, and other materials related to such
  11. -- distribution and use acknowledge that the software was developed
  12. -- by the University of California, Irvine.  The name of the
  13. -- University may not be used to endorse or promote products derived
  14. -- from this software without specific prior written permission.
  15. -- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  16. -- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  17. -- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18.  
  19. -- TITLE parser for aflex
  20. -- AUTHOR: John Self (UCI)
  21. -- DESCRIPTION lalr(1) grammar for input to AYACC.
  22. -- NOTES
  23. -- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/parse.y,v 1.15 90/01/17 15:49:56 self Exp Locker: self $ 
  24.  
  25. %token CHAR NUMBER SECTEND SCDECL XSCDECL WHITESPACE NAME PREVCCL EOF_OP
  26. %token NEWLINE
  27.  
  28. %with TEXT_IO
  29. %with ccl
  30. %with NFA
  31. %with Parse_Shift_Reduce
  32. %with Parse_Goto
  33. %with misc_defs
  34. %use misc_defs
  35. %with external_file_manager
  36. %use external_file_manager
  37.  
  38. {
  39.   subtype YYSType is Integer;
  40. }
  41.  
  42. %%
  43. goal            :  initlex sect1 sect1end sect2 initforrule
  44.             { -- add default rule
  45.  
  46.             pat := ccl.cclinit;
  47.             ccl.cclnegate( pat );
  48.  
  49.             def_rule := nfa.mkstate( -pat );
  50.  
  51.             nfa.finish_rule( def_rule, false, 0, 0 );
  52.  
  53.             for i in 1 .. lastsc loop
  54.                 scset(i) := nfa.mkbranch( scset(i), def_rule );
  55.             end loop;
  56.             
  57.             if ( spprdflt ) then
  58.                 text_io.put(temp_action_file,
  59.                     "raise AFLEX_SCANNER_JAMMED;");
  60.             else
  61.                 text_io.put( temp_action_file, "ECHO" );
  62.  
  63.             text_io.put_line( temp_action_file, ";" );
  64.             end if;
  65.             }
  66.         ;
  67.  
  68. initlex         :
  69.             {
  70.             -- initialize for processing rules
  71.  
  72.                    -- create default DFA start condition
  73.             sym.scinstal( tstring.vstr("INITIAL"), false );
  74.             }
  75.         ;
  76.             
  77. sect1        :  sect1 startconddecl WHITESPACE namelist1 NEWLINE
  78.         |
  79.         |  error NEWLINE
  80.             { misc.synerr( "unknown error processing section 1" );}
  81.         ;
  82.  
  83. sect1end    :  SECTEND
  84.         ;
  85.  
  86. startconddecl   :  SCDECL
  87.             {
  88.              -- these productions are separate from the s1object
  89.              -- rule because the semantics must be done before
  90.              -- we parse the remainder of an s1object
  91.             
  92.  
  93.             xcluflg := false;
  94.             }
  95.         
  96.         |  XSCDECL
  97.             { xcluflg := true; }
  98.         ;
  99.  
  100. namelist1    :  namelist1 WHITESPACE NAME
  101.             { sym.scinstal( nmstr, xcluflg ); }
  102.  
  103.         |  NAME
  104.             { sym.scinstal( nmstr, xcluflg ); }
  105.  
  106.         |  error
  107.                         { misc.synerr( "bad start condition list" ); }
  108.         ;
  109.  
  110. sect2           :  sect2 initforrule aflexrule NEWLINE
  111.         |
  112.         ;
  113.  
  114. initforrule     :
  115.             {
  116.             -- initialize for a parse of one rule
  117.             trlcontxt := false;
  118.             variable_trail_rule := false;
  119.             varlength := false;
  120.             trailcnt := 0;
  121.             headcnt := 0;
  122.             rulelen := 0;
  123.             current_state_enum := STATE_NORMAL;
  124.             previous_continued_action := continued_action;
  125.             nfa.new_rule;
  126.             }
  127.         ;
  128.  
  129. aflexrule        :  scon '^' re eol 
  130.                         {
  131.             pat := nfa.link_machines( $3, $4 );
  132.             nfa.finish_rule( pat, variable_trail_rule,
  133.                      headcnt, trailcnt );
  134.  
  135.             for i in 1 .. actvp loop
  136.                 scbol(actvsc(i)) :=
  137.                 nfa.mkbranch( scbol(actvsc(i)), pat );
  138.             end loop;    
  139.                 
  140.             if ( not bol_needed ) then
  141.                 bol_needed := true;
  142.  
  143.                 if ( performance_report ) then
  144.                 text_io.put( Standard_Error,
  145.             "'^' operator results in sub-optimal performance");
  146.                     text_io.new_line(Standard_Error);
  147.                             end if;
  148.             end if;
  149.             }
  150.  
  151.         |  scon re eol 
  152.                         {
  153.             pat := nfa.link_machines( $2, $3 );
  154.             nfa.finish_rule( pat, variable_trail_rule,
  155.                      headcnt, trailcnt );
  156.  
  157.             for i in 1 .. actvp loop
  158.                 scset(actvsc(i)) := 
  159.                 nfa.mkbranch( scset(actvsc(i)), pat );
  160.             end loop;
  161.                 }
  162.                 |  '^' re eol 
  163.             {
  164.             pat := nfa.link_machines( $2, $3 );
  165.             nfa.finish_rule( pat, variable_trail_rule,
  166.                      headcnt, trailcnt );
  167.  
  168.             -- add to all non-exclusive start conditions,
  169.             -- including the default (0) start condition
  170.  
  171.             for i in 1 .. lastsc loop
  172.                 if ( not scxclu(i) ) then
  173.                 scbol(i) := nfa.mkbranch( scbol(i), pat );
  174.                 end if;    
  175.             end loop;
  176.  
  177.             if ( not bol_needed ) then
  178.                 bol_needed := true;
  179.  
  180.                 if ( performance_report ) then
  181.                 text_io.put( Standard_Error,
  182.             "'^' operator results in sub-optimal performance");
  183.                     text_io.new_line(Standard_Error);
  184.                 end if;
  185.             end if;
  186.                         }
  187.                 |  re eol 
  188.             {
  189.             pat := nfa.link_machines( $1, $2 );
  190.             nfa.finish_rule( pat, variable_trail_rule,
  191.                      headcnt, trailcnt );
  192.  
  193.             for i in 1 .. lastsc loop
  194.                 if ( not scxclu(i) ) then
  195.                 scset(i) := nfa.mkbranch( scset(i), pat );
  196.                 end if;
  197.             end loop;
  198.             }
  199.  
  200.                 |  scon EOF_OP
  201.             { build_eof_action; }
  202.  
  203.                 |  EOF_OP
  204.             {
  205.             -- this EOF applies only to the INITIAL start cond.
  206.             actvp := 1;
  207.             actvsc(actvp) := 1;
  208.             build_eof_action;
  209.             }
  210.  
  211.                 |  error
  212.             { misc.synerr( "unrecognized rule" ); }
  213.         ;
  214.  
  215. scon            :  '<' namelist2 '>'
  216.         ;
  217.  
  218. namelist2       :  namelist2 ',' NAME
  219.                         {
  220.             scnum := sym.sclookup( nmstr );
  221.             if (scnum = 0 ) then
  222.                     text_io.put( Standard_Error,
  223.                      "undeclared start condition ");
  224.                     tstring.put( Standard_Error, nmstr );
  225.                 main_body.aflexend( 1 );
  226.             else
  227.               actvp := actvp + 1;
  228.                 actvsc(actvp) := scnum;
  229.             end if;
  230.             }
  231.  
  232.         |  NAME
  233.             {
  234.             scnum := sym.sclookup( nmstr );
  235.             if (scnum = 0 ) then
  236.                     text_io.put( Standard_Error,
  237.                     "undeclared start condition ");
  238.                     tstring.put( Standard_Error,     nmstr );
  239.                 main_body.aflexend ( 1 );
  240.             else
  241.                 actvp := 1;
  242.                 actvsc(actvp) := scnum;
  243.             end if;
  244.             }
  245.  
  246.         |  error
  247.             { misc.synerr( "bad start condition list" ); }
  248.         ;
  249.  
  250. eol             :  '$'
  251.                         {
  252.             if trlcontxt then
  253.                 misc.synerr( "trailing context used twice" );
  254.                 $$ := nfa.mkstate( SYM_EPSILON );
  255.             else
  256.                 trlcontxt := true;
  257.  
  258.                 if ( not varlength ) then
  259.                 headcnt := rulelen;
  260.                 end if;
  261.  
  262.                 rulelen := rulelen + 1;
  263.                 trailcnt := 1;
  264.  
  265.                 eps := nfa.mkstate( SYM_EPSILON );
  266.                 $$ := nfa.link_machines( eps,
  267.                       nfa.mkstate( CHARACTER'POS(ASCII.LF) ) );
  268.                         end if;
  269.             }
  270.  
  271.         |
  272.                 {
  273.                 $$ := nfa.mkstate( SYM_EPSILON );
  274.  
  275.             if ( trlcontxt ) then
  276.                 if ( varlength and (headcnt = 0) ) then
  277.                 -- both head and trail are variable-length
  278.                 variable_trail_rule := true;
  279.                 else
  280.                 trailcnt := rulelen;
  281.                 end if;
  282.                         end if;
  283.                 }
  284.         ;
  285.  
  286. re              :  re '|' series
  287.                         {
  288.             varlength := true;
  289.  
  290.             $$ := nfa.mkor( $1, $3 );
  291.             }
  292.  
  293.         |  re2 series
  294.             {
  295.             if ( transchar(lastst($2)) /= SYM_EPSILON ) then
  296.                 -- provide final transition \now/ so it
  297.                 -- will be marked as a trailing context
  298.                 -- state
  299.  
  300.                 $2 := nfa.link_machines( $2, nfa.mkstate( SYM_EPSILON ) );
  301.             end if;
  302.  
  303.             nfa.mark_beginning_as_normal( $2 );
  304.             current_state_enum := STATE_NORMAL;
  305.  
  306.             if ( previous_continued_action ) then
  307.                 -- we need to treat this as variable trailing
  308.                 -- context so that the backup does not happen
  309.                 -- in the action but before the action switch
  310.                 -- statement.  If the backup happens in the
  311.                 -- action, then the rules "falling into" this
  312.                 -- one's action will *also* do the backup,
  313.                 -- erroneously.
  314.  
  315.                     if ( (not varlength) or  headcnt /= 0 ) then
  316.                      text_io.put( Standard_Error,
  317.                               "alex: warning - trailing context rule at line");
  318.                                      int_io.put(Standard_Error, linenum);
  319.                      text_io.put( Standard_Error,
  320.                            "made variable because of preceding '|' action" );
  321.                                      int_io.put(Standard_Error, linenum);
  322.                                 end if;
  323.  
  324.                 -- mark as variable
  325.                 varlength := true;
  326.                 headcnt := 0;
  327.                         end if;
  328.             
  329.             if ( varlength and (headcnt = 0) ) then
  330.                 -- variable trailing context rule
  331.                 -- mark the first part of the rule as the accepting
  332.                 -- "head" part of a trailing context rule
  333.  
  334.                 -- by the way, we didn't do this at the beginning
  335.                 -- of this production because back then
  336.                 -- current_state_enum was set up for a trail
  337.                 -- rule, and add_accept() can create a new
  338.                 -- state ...
  339.  
  340.                 nfa.add_accept( $1,
  341.                                    misc.set_yy_trailing_head_mask(num_rules) );
  342.                         end if;
  343.  
  344.             $$ := nfa.link_machines( $1, $2 );
  345.             }
  346.  
  347.         |  series
  348.             { $$ := $1; }
  349.         ;
  350.  
  351.  
  352. re2        :  re '/'
  353.             {
  354.             -- this rule is separate from the others for "re" so
  355.             -- that the reduction will occur before the trailing
  356.             -- series is parsed
  357.  
  358.             if ( trlcontxt ) then
  359.                 misc.synerr( "trailing context used twice" );
  360.             else
  361.                 trlcontxt := true;
  362.             end if;    
  363.  
  364.             if ( varlength ) then
  365.                 -- we hope the trailing context is fixed-length
  366.                 varlength := false;
  367.             else
  368.                 headcnt := rulelen;
  369.             end if;    
  370.  
  371.             rulelen := 0;
  372.  
  373.             current_state_enum := STATE_TRAILING_CONTEXT;
  374.             $$ := $1;
  375.             }
  376.         ;
  377.  
  378. series          :  series singleton
  379.                         {
  380.             -- this is where concatenation of adjacent patterns
  381.             -- gets done
  382.  
  383.             $$ := nfa.link_machines( $1, $2 );
  384.             }
  385.  
  386.         |  singleton
  387.             { $$ := $1; }
  388.         ;
  389.  
  390. singleton       :  singleton '*'
  391.                         {
  392.             varlength := true;
  393.  
  394.             $$ := nfa.mkclos( $1 );
  395.             }
  396.             
  397.         |  singleton '+'
  398.             {
  399.             varlength := true;
  400.  
  401.             $$ := nfa.mkposcl( $1 );
  402.             }
  403.  
  404.         |  singleton '?'
  405.             {
  406.             varlength := true;
  407.  
  408.             $$ := nfa.mkopt( $1 );
  409.             }
  410.  
  411.         |  singleton '{' NUMBER ',' NUMBER '}'
  412.             {
  413.             varlength := true;
  414.  
  415.             if ( ($3 > $5) or ($3 < 0) ) then
  416.                 misc.synerr( "bad iteration values" );
  417.                 $$ := $1;
  418.             else
  419.                 if ( $3 = 0 ) then
  420.                 $$ := nfa.mkopt( nfa.mkrep( $1, $3, $5 ) );
  421.                 else
  422.                 $$ := nfa.mkrep( $1, $3, $5 );
  423.                 end if;
  424.                         end if;
  425.             }
  426.                 
  427.         |  singleton '{' NUMBER ',' '}'
  428.             {
  429.             varlength := true;
  430.  
  431.             if ( $3 <= 0 ) then
  432.                 misc.synerr( "iteration value must be positive" );
  433.                 $$ := $1;
  434.             else
  435.                 $$ := nfa.mkrep( $1, $3, INFINITY );
  436.             end if;    
  437.             }
  438.  
  439.         |  singleton '{' NUMBER '}'
  440.             {
  441.             -- the singleton could be something like "(foo)",
  442.             -- in which case we have no idea what its length
  443.             -- is, so we punt here.
  444.  
  445.             varlength := true;
  446.  
  447.             if ( $3 <= 0 ) then
  448.                 misc.synerr( "iteration value must be positive" );
  449.                 $$ := $1;
  450.             else
  451.                 $$ := nfa.link_machines( $1, nfa.copysingl( $1, $3 - 1 ) );
  452.             end if;    
  453.             }
  454.  
  455.         |  '.'
  456.             {
  457.             if ( not madeany ) then
  458.                 -- create the '.' character class
  459.                 anyccl := ccl.cclinit;
  460.                 ccl.ccladd( anyccl, ASCII.LF );
  461.                 ccl.cclnegate( anyccl );
  462.  
  463.                 if ( useecs ) then
  464.                 ecs.mkeccl(
  465.                ccltbl(cclmap(anyccl)..cclmap(anyccl) + ccllen(anyccl)),
  466.                     ccllen(anyccl), nextecm,
  467.                     ecgroup, CSIZE );
  468.                 end if;
  469.                 madeany := true;
  470.                         end if;
  471.  
  472.             rulelen := rulelen + 1;
  473.  
  474.             $$ := nfa.mkstate( -anyccl );
  475.             }
  476.  
  477.         |  fullccl
  478.             {
  479.             if ( not cclsorted ) then
  480.                 -- sort characters for fast searching.  We use a
  481.                 -- shell sort since this list could be large.
  482.  
  483. --                misc.cshell( ccltbl + cclmap($1), ccllen($1) );
  484.               misc.cshell( ccltbl(cclmap($1)..cclmap($1) + ccllen($1)),
  485.                    ccllen($1) );
  486.             end if;
  487.  
  488.             if ( useecs ) then
  489.             ecs.mkeccl( ccltbl(cclmap($1)..cclmap($1) + ccllen($1)),
  490.                 ccllen($1),nextecm, ecgroup, CSIZE );
  491.             end if;
  492.                      
  493.             rulelen := rulelen + 1;
  494.  
  495.             $$ := nfa.mkstate( -$1 );
  496.             }
  497.  
  498.         |  PREVCCL
  499.             {
  500.             rulelen := rulelen + 1;
  501.  
  502.             $$ := nfa.mkstate( -$1 );
  503.             }
  504.  
  505.         |  '"' string '"'
  506.             { $$ := $2; }
  507.  
  508.         |  '(' re ')'
  509.             { $$ := $2; }
  510.  
  511.         |  CHAR
  512.             {
  513.             rulelen := rulelen + 1;
  514.  
  515.             if ( $1 = CHARACTER'POS(ASCII.NUL) ) then
  516.                 misc.synerr( "null in rule" );
  517.             end if;    
  518.  
  519.             if ( caseins and ($1 >= CHARACTER'POS('A')) and ($1 <= CHARACTER'POS('Z')) ) then
  520.                 $1 := misc.clower( $1 );
  521.             end if;
  522.  
  523.             $$ := nfa.mkstate( $1 );
  524.             }
  525.         ;
  526.  
  527. fullccl        :  '[' ccl ']'
  528.             { $$ := $2; }
  529.  
  530.         |  '[' '^' ccl ']'
  531.             {
  532.             -- *Sigh* - to be compatible Unix lex, negated ccls
  533.             -- match newlines
  534.             ccl.cclnegate( $3 );
  535.             $$ := $3;
  536.             }
  537.         ;
  538.  
  539. ccl             :  ccl CHAR '-' CHAR
  540.                         {
  541.             if ( $2 > $4 ) then
  542.                 misc.synerr( "negative range in character class" );
  543.             else
  544.                 if ( caseins ) then
  545.                 if ( ($2 >= CHARACTER'POS('A')) and ($2 <= CHARACTER'POS('Z')) ) then
  546.                     $2 := misc.clower( $2 );
  547.                 end if;                        
  548.                 if ( ($4 >= CHARACTER'POS('A')) and ($4 <= CHARACTER'POS('Z')) ) then
  549.                     $4 := misc.clower( $4 );
  550.                 end if;    
  551.                             end if;
  552.  
  553.                 for i in $2 .. $4 loop
  554.                     ccl.ccladd( $1, CHARACTER'VAL(i) );
  555.                             end loop;
  556.                 
  557.                 -- keep track if this ccl is staying in
  558.                 -- alphabetical order
  559.  
  560.                 cclsorted := cclsorted and ($2 > lastchar);
  561.                 lastchar := $4;
  562.                         end if;
  563.             
  564.             $$ := $1;
  565.             }
  566.  
  567.         |  ccl CHAR
  568.                 {
  569.             if ( caseins ) then
  570.                 if ( ($2 >= CHARACTER'POS('A')) and ($2 <= CHARACTER'POS('Z')) ) then
  571.                 $2 := misc.clower( $2 );
  572.                             end if;
  573.             end if;    
  574.             ccl.ccladd( $1, CHARACTER'VAL($2) );
  575.             cclsorted := cclsorted and ($2 > lastchar);
  576.             lastchar := $2;
  577.             $$ := $1;
  578.             }
  579.  
  580.         |
  581.             {
  582.             cclsorted := true;
  583.             lastchar := 0;
  584.             $$ := ccl.cclinit;
  585.             }
  586.         ;
  587.  
  588. string        :  string CHAR
  589.                         {
  590.             if ( caseins ) then
  591.                 if ( ($2 >= CHARACTER'POS('A')) and ($2 <= CHARACTER'POS('Z')) ) then
  592.                 $2 := misc.clower( $2 );
  593.                 end if;
  594.             end if;    
  595.  
  596.             rulelen := rulelen + 1;
  597.  
  598.             $$ := nfa.link_machines( $1, nfa.mkstate( $2 ) );
  599.             }
  600.  
  601.         |
  602.             { $$ := nfa.mkstate( SYM_EPSILON ); }
  603.         ;
  604.  
  605. %%
  606.  
  607. with Parse_Tokens, Parse_Goto, Parse_Shift_Reduce, Text_IO, scanner;
  608. with NFA, ccl, misc, misc_defs, sym, ecs, aflex_scanner;
  609. with tstring, int_io, main_body, text_io, external_file_manager;
  610. use aflex_scanner, external_file_manager;
  611.  
  612. package parser is
  613.   procedure build_eof_action;
  614.   procedure yyerror(msg: string);
  615.   procedure YYParse;
  616.   def_rule:integer;
  617. end parser;
  618.  
  619. package body parser is
  620. -- build_eof_action - build the "<<EOF>>" action for the active start
  621. --                    conditions
  622.  
  623. use text_io, misc_defs;
  624. procedure build_eof_action is
  625. begin
  626.     text_io.put( temp_action_file, "when " );
  627.     for i in 1..actvp loop
  628.     if ( sceof(actvsc(i)) ) then
  629.         text_io.put( Standard_Error,
  630.         "multiple <<EOF>> rules for start condition ");
  631.         tstring.put( Standard_Error, scname(actvsc(i)));
  632.         main_body.aflexend(1);
  633.     else
  634.         sceof(actvsc(i)) := true;
  635.         text_io.put( temp_action_file, "YY_END_OF_BUFFER +" );
  636.         tstring.put( temp_action_file,  scname(actvsc(i)) );
  637.         text_io.put_line( temp_action_file, " + 1 " );
  638.         if (i /= actvp) then
  639.             text_io.put_line( temp_action_file, " |" );
  640.         else
  641.             text_io.put_line( temp_action_file, " =>" );
  642.         end if;
  643.         end if;
  644.     end loop;
  645.     misc.line_directive_out( temp_action_file );
  646. end build_eof_action;
  647.  
  648. --  yyerror - eat up an error message from the parser
  649. -- 
  650. --  synopsis
  651. --     char msg[];
  652. --     yyerror( msg );
  653.  
  654. procedure yyerror( msg : string ) is
  655. begin
  656. null;
  657. end yyerror;
  658.  
  659. use  Parse_Goto, Parse_Shift_Reduce, Text_IO, misc_defs, tstring;
  660. ##
  661. end parser;
  662.